﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using HadronData;

namespace Hadron.Entities
{
    enum StationType
    {
        Fuel,
        Repair,
        Cargo
    }

    class Station
        : LandEntity
    {
        private static Polygon s_polygonVisible;
        private StationType m_stationType;
        private Polygon m_polygonContact, m_polygonVisible;
        private ParticleSystem m_particleSystemFuel1, m_particleSystemFuel2;
        private float m_fTime;
        private bool m_bReplenish;
        private Color m_colourStation;

        public Station(EntityMarker p_entityMarker, Environment p_environment, StationType p_stationType)
            : base(p_entityMarker, p_environment)
        {
            m_stationType = p_stationType;
            m_bReplenish = false;

            if (s_polygonVisible == null)
            {
                s_polygonVisible = new Polygon();
                s_polygonVisible.Edges.Add(new Edge(-20.0f, -2.0f, 20.0f, -2.0f, Color.LightGray));
                s_polygonVisible.Edges.Add(new Edge(-20.0f, -2.0f, -28.0f, -4.0f, Color.LightGray));
                s_polygonVisible.Edges.Add(new Edge(20.0f, -2.0f, 28.0f, -4.0f, Color.LightGray));
                s_polygonVisible.Edges.Add(new Edge(-28.0f, -4.0f, -28.0f, 0.0f, Color.LightGray));
                s_polygonVisible.Edges.Add(new Edge(28.0f, -4.0f, 28.0f, 0.0f, Color.LightGray));
                s_polygonVisible.Edges.Add(new Edge(-28.0f, 0.0f, 28.0f, 0.0f, Color.LightGray));
                s_polygonVisible.UpdateBounds();
            }

            m_polygonContact = new Polygon();
            m_polygonContact.Edges.Add(new Edge());

            m_polygonVisible = new Polygon(s_polygonVisible);
            m_polygonVisible.Transform(m_trnPlacement);

            switch (m_stationType)
            {
                case StationType.Fuel: m_colourStation = new Color(0, 128, 255); break;
                case StationType.Repair: m_colourStation = new Color(64, 255, 0); break;
                default: m_colourStation = Color.Orange; break;
            }

            m_particleSystemFuel1 = new ParticleSystem(32, 0, 1.0f);
            m_particleSystemFuel2 = new ParticleSystem(32, 0, 1.0f);
            m_particleSystemFuel1.EmissionVelocityVariance = 16.0f;
            m_particleSystemFuel2.EmissionVelocityVariance = 16.0f;
            m_particleSystemFuel1.ParticleColours = new Color[] { m_colourStation, Color.Black };
            m_particleSystemFuel2.ParticleColours = new Color[] { m_colourStation, Color.Black };
            m_particleSystemFuel1.EmissionRate = 32.0f;
            m_particleSystemFuel2.EmissionRate = 32.0f;

            m_circleBounds = s_polygonVisible.GetBoundingCircle(Vector2.Zero);
        }

        public override void Update(GameTime p_gameTime)
        {
            base.Update(p_gameTime);

            m_circleBounds.Centre = m_trnPlacement.Translation;

            float fDeltaTime = (float)p_gameTime.ElapsedGameTime.TotalSeconds;
            m_fTime = (float) p_gameTime.TotalGameTime.TotalSeconds;

            if (m_bReplenish)
            {

                if (m_stationType == StationType.Fuel)
                    m_environment.PlayerShip.Fuel += fDeltaTime * 20.0f;
                else if (m_stationType == StationType.Repair)
                    m_environment.PlayerShip.Integrity += fDeltaTime * 5.0f;
            }

            // update contact geometry
            m_polygonContact.Edges[0].Start = m_trnPlacement.Apply(Vector2.Zero);
            m_polygonContact.Edges[0].End = m_trnPlacement.Apply(new Vector2(0.0f, -20.0f));
            
            // transform visible geometry
            m_polygonVisible.Transform(m_trnPlacement, s_polygonVisible);

            m_particleSystemFuel1.Position = m_trnPlacement.Apply(new Vector2(-24.0f, 0.0f));
            m_particleSystemFuel2.Position = m_trnPlacement.Apply(new Vector2( 24.0f, 0.0f));
            m_particleSystemFuel1.EmissionVelocity = m_trnPlacement.RotationComponent.Apply(new Vector2(16.0f, -16.0f));
            m_particleSystemFuel2.EmissionVelocity = m_trnPlacement.RotationComponent.Apply(new Vector2(-16.0f, -16.0f));

            m_particleSystemFuel1.Active = m_particleSystemFuel2.Active = m_bReplenish;

            m_particleSystemFuel1.Update(p_gameTime);
            m_particleSystemFuel2.Update(p_gameTime);

            // attract player ship if close to fuel or repair station
            PlayerShip playerShip = m_environment.PlayerShip;
            if (m_stationType != StationType.Cargo
                && playerShip.HullGeometry.Intersects(m_polygonContact)
                && !playerShip.ForwardThruster)
            {
                float fDeltaOrientation = Orientation - MathHelper.PiOver2 - playerShip.Orientation;
                if (fDeltaOrientation > MathHelper.Pi)
                    fDeltaOrientation -= MathHelper.TwoPi;
                if (fDeltaOrientation < -MathHelper.Pi)
                    fDeltaOrientation += MathHelper.TwoPi;
                playerShip.Orientation += fDeltaOrientation * fDeltaTime;

                Transformation trnPerp = m_trnPlacement.RotationComponent;
                trnPerp.Rotation -= MathHelper.PiOver2;
                Vector2 vecDeltaPosition = Position + trnPerp.RotationDirection * 18.0f - playerShip.Position;
                playerShip.Position += vecDeltaPosition * fDeltaTime;
                playerShip.Velocity *= 0.1f * fDeltaTime;
            }
        }

        public override void Draw(SpriteBatch p_spriteBatch)
        {
            m_polygonVisible.Draw(p_spriteBatch);

            // glow
            float fIntensity = 0.75f + (float) Math.Cos(m_fTime * MathHelper.Pi) * 0.25f;
            Vector3 vecStationColour = m_colourStation.ToVector3();
            p_spriteBatch.Draw(AssetManager.Textures.StationGlow, Position, null,
                new Color(vecStationColour.X * fIntensity, vecStationColour.Y * fIntensity, vecStationColour.Z * fIntensity),
                Orientation, new Vector2(32.0f, 64.0f), 1.0f, SpriteEffects.None, 0.0f);

            // replenishing particles
            m_particleSystemFuel1.Draw(p_spriteBatch);
            m_particleSystemFuel2.Draw(p_spriteBatch);

            // sign
            Texture2D textureSign = null;
            switch (m_stationType)
            {
                case StationType.Fuel: textureSign = AssetManager.Textures.StationFuel; break;
                case StationType.Repair: textureSign = AssetManager.Textures.StationRepair; break;
                case StationType.Cargo: textureSign = AssetManager.Textures.StationCargo; break;
            }
            p_spriteBatch.Draw(textureSign, Position, null,
                new Color(fIntensity, fIntensity, fIntensity),
                Orientation, new Vector2(32.0f, 64.0f), 1.0f, SpriteEffects.None, 0.0f);

            // arrow
            float fOffset = (m_fTime * 10.0f) % 10.0f;
            fIntensity = 1.0f - fOffset * 0.1f;
            p_spriteBatch.Draw(AssetManager.Textures.StationArrow, Position, null,
                new Color(fIntensity, fIntensity, fIntensity),
                Orientation, new Vector2(32.0f, 64.0f - fOffset), 1.0f, SpriteEffects.None, 0.0f);
        }

        public override void OnPlayerHit()
        {
            if (Type == EntityType.FuelStation
                || Type == EntityType.RepairStation)
                m_bReplenish = m_environment.PlayerShip.Landed;
        }

        public bool Replenish
        {
            get { return m_bReplenish; }
            set { m_bReplenish = value; }
        }

        public override bool Destructuble
        {
            get { return false; }
        }

        public override bool Hostile
        {
            get { return false; }
        }

        public override HadronData.EntityType Type
        {
            get
            {
                switch (m_stationType)
                {
                    case StationType.Fuel: return EntityType.FuelStation;
                    case StationType.Repair: return EntityType.RepairStation;
                    default: return EntityType.CargoStation;
                }
            }
        }

        public override Geometry Geometry
        {
            get { return m_polygonContact; }
        }
    }
}
